package com.shangyueshang.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.shangyueshang.enums.DelFlag;
import com.shangyueshang.common.SysConstants;
import com.shangyueshang.enums.UserStatus;
import com.shangyueshang.mapper.ShopMapper;
import com.shangyueshang.mapper.SysUserMapper;
import com.shangyueshang.mapper.SysUserRoleMapper;
import com.shangyueshang.model.*;
import com.shangyueshang.request.PageReq;
import com.shangyueshang.request.PasswordDTO;
import com.shangyueshang.request.SysUserDTO;
import com.shangyueshang.response.HttpResult;
import com.shangyueshang.response.PageResult;
import com.shangyueshang.service.SysMenuService;
import com.shangyueshang.service.SysRoleService;
import com.shangyueshang.service.SysUserService;
import com.shangyueshang.utils.MyPageHelper;
import com.shangyueshang.utils.PasswordUtil;
import com.shangyueshang.utils.SecurityUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author JokeyFeng
 * @date: 2022/1/4
 * @project: shangyueshang
 * @package: com.shangyueshang.service.impl
 * @comment:
 */
@Slf4j
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
	
	@Resource
	private ShopMapper shopMapper;
	
	@Resource
	private SysRoleService sysRoleService;
	
	@Resource
	private SysMenuService sysMenuService;
	
	@Resource
	private SysUserRoleMapper sysUserRoleMapper;
	
	private static final String DEFAULT_PASSWORD = "123@qwe";
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public HttpResult<Void> save(SysUserDTO sysUser) {
		SysUser user = new SysUser();
		SysUser oldUser = super.getById(sysUser.getId());
		if (Objects.nonNull(oldUser)) {
			if (SysConstants.admin.equalsIgnoreCase(sysUser.getName())) {
				return HttpResult.fail("超级管理员不允许修改");
			}
		} else {
			user.setCreator(SecurityUtil.getUsername());
			user.setCreateTime(LocalDateTime.now());
		}
		
		if (
				(oldUser =
						super.getOne(
								new LambdaQueryWrapper<SysUser>().eq(SysUser::getName, sysUser.getName())
						)
				) != null
						&& !sysUser.getId().equals(oldUser.getId())
		) {
			return HttpResult.fail("用户名已存在");
		}
		
		BeanUtils.copyProperties(sysUser, user);
		user.setLastUpdator(SecurityUtil.getUsername());
		user.setLastUpdateTime(LocalDateTime.now());
		
		user.setPassword(Optional.ofNullable(user.getPassword()).orElse(DEFAULT_PASSWORD));
		String salt = PasswordUtil.getSalt();
		String password = PasswordUtil.encode(user.getPassword(), salt);
		user.setSalt(salt);
		user.setPassword(password);
		//保存用户数据
		super.saveOrUpdate(user);
		
		if (sysUser.getId() != null) {
			log.info("delete roles result:{}", sysUserRoleMapper.deleteByUserId(sysUser.getId()));
		}
		//todo 如果是禁用，则将用户踢下线
		if (sysUser.getStatus().equals(UserStatus.disabled)) {
		
		}
		
		//新增用户角色
		sysUser.getUserRoles().forEach(userRole -> {
			userRole.setUserId(user.getId());
			sysUserRoleMapper.insert(userRole);
		});
		
		return HttpResult.ok();
	}
	
	@Override
	public SysUser findByName(String name) {
		SysUser sysUser = getBaseMapper().find(name);
		if (Objects.nonNull(sysUser)) {
			this.findUserRoles(sysUser);
			//如果是超级管理员则查询所有店铺
			if (sysUser.getRoleNames().contains(SysConstants.super_admin)) {
				List<String> shops =
						shopMapper.selectList(
								new LambdaQueryWrapper<Shop>()
										.select(Shop::getName)
						)
								.stream()
								.map(Shop::getName)
								.collect(Collectors.toList());
				sysUser.setAuthorizedShops(shops);
			}
		}
		
		return sysUser;
	}
	
	@Override
	public PageResult<SysUser> findPage(PageReq pageReq) {
		QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq(SysConstants.del_flag, DelFlag.NO.val);
		pageReq.getLineParams().forEach(queryWrapper::eq);
		PageInfo<SysUser> pageInfo =
				PageHelper.startPage(
						pageReq.getPageNum(),
						pageReq.getPageSize()
				)
						.doSelectPageInfo(
								() -> super.list(queryWrapper)
						);
		//加载用户角色
		pageInfo.getList().forEach(this::findUserRoles);
		return MyPageHelper.getPageResult(pageInfo);
	}
	
	/**
	 * 加载用户角色
	 *
	 * @param sysUser
	 */
	private void findUserRoles(SysUser sysUser) {
		List<SysUserRole> userRoles = sysUserRoleMapper.findUserRoles(sysUser.getId());
		sysUser.setUserRoles(userRoles);
		sysUser.setRoleNames(this.getRoleNames(userRoles));
	}
	
	/**
	 * 获取角色名称
	 *
	 * @param userRoles
	 * @return
	 */
	private String getRoleNames(List<SysUserRole> userRoles) {
		StringBuilder sb = new StringBuilder();
		for (Iterator<SysUserRole> iter = userRoles.iterator(); iter.hasNext(); ) {
			SysUserRole userRole = iter.next();
			SysRole sysRole = sysRoleService.getById(userRole.getRoleId());
			if (Objects.isNull(sysRole)) {
				continue;
			}
			sb.append(sysRole.getName());
			if (iter.hasNext()) {
				sb.append(", ");
			}
		}
		return sb.toString();
	}
	
	@Override
	public List<SysUserRole> findUserRoles(Long userId) {
		return sysUserRoleMapper.findUserRoles(userId);
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void delete(List<Long> ids) {
		ids.forEach(userId -> {
			baseMapper.deleteById(userId);
			sysUserRoleMapper.deleteByUserId(userId);
		});
	}
	
	@Override
	public Set<String> findPermissions(String userName) {
		Set<String> permissions = new HashSet<>();
		List<SysMenu> sysMenus = sysMenuService.findByUser(userName);
		for (SysMenu menu : sysMenus) {
			if (StringUtils.hasText(menu.getPerms())) {
				permissions.add(menu.getPerms());
			}
		}
		return permissions;
	}
	
	@Override
	public HttpResult<Void> resetPassword(PasswordDTO passwordDTO) {
		//校验原密码是否一致
		SysUser sysUser = this.baseMapper.find(SecurityUtil.getUsername());
		if (Objects.isNull(sysUser)) {
			return HttpResult.fail("修改失败");
		}
		//校验原密码
		boolean matches = PasswordUtil.matches(sysUser.getSalt(), passwordDTO.getOldPassword(), sysUser.getPassword());
		if (!matches) {
			return HttpResult.fail("旧密码错误");
		}
		String salt = PasswordUtil.getSalt();
		String enPassword = PasswordUtil.encode(passwordDTO.getNewPassword(), salt);
		sysUser.setPassword(enPassword);
		sysUser.setSalt(salt);
		super.updateById(sysUser);
		return HttpResult.ok();
	}
}
